/*
 * INET		An implementation of the TCP/IP protocol suite for the LINUX
 *		operating system.  INET is implemented using the  BSD Socket
 *		interface as the means of communication with the user level.
 *
 *		Definitions for the AF_INET socket handler.
 *
 * Version:	@(#)sock.h	1.0.4	05/13/93
 *
 * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
 *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *		Corey Minyard <wf-rch!minyard@relay.EU.net>
 *		Florian La Roche <flla@stud.uni-sb.de>
 *
 * Fixes:
 *		Alan Cox	:	Volatiles in skbuff pointers. See
 *					skbuff comments. May be overdone,
 *					better to prove they can be removed
 *					than the reverse.
 *		Alan Cox	:	Added a zapped field for tcp to note
 *					a socket is reset and must stay shut up
 *		Alan Cox	:	New fields for options
 *	Pauline Middelink	:	identd support
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 */
#ifndef _SOCK_H
#define _SOCK_H

#include <linux/timer.h>
#include <linux/ip.h>		/* struct options */
#include <linux/tcp.h>		/* struct tcphdr */
#include <linux/config.h>

#include <linux/skbuff.h>	/* struct sk_buff */
#include "protocol.h"		/* struct inet_protocol */
#ifdef CONFIG_AX25
#include "ax25.h"
#endif
#ifdef CONFIG_IPX
#include "ipx.h"
#endif
#ifdef CONFIG_ATALK
#include <linux/atalk.h>
#endif

#include <linux/igmp.h>

#define SOCK_ARRAY_SIZE	256		/* Think big (also on some systems a byte is faster */


/*
 * This structure really needs to be cleaned up.
 * Most of it is for TCP, and not used by any of
 * the other protocols.
 */
struct sock {
  struct options		*opt; // IP选项
  volatile unsigned long	wmem_alloc;  // 当前写缓冲区大小，该值不可大于系统规定的最大值
  volatile unsigned long	rmem_alloc; // 当前读缓冲区大小，该值不可大于系统规定最大值
  
  // 以下三个字段用于 TCP 协议中为保证可靠数据传输而使用的序列号
  unsigned long			write_seq;  // 应用程序下一次写数据时所对应的第一个字节的序列号
  // 本地将要发送的下一个数据包中第一个字节对应的序列号。该字段对应TCP首部中序列号字段，表示本数据包中所包含数据第一个字节的序列号
  unsigned long			sent_seq;
  // 本地希望从远端接收的下一个数据的序列号。该字段对应 TCP 首部中应答序列号字段
  unsigned long			acked_seq;

  /**
   * 应用程序尚未读取数据的第一个序列号
   * 例如 copied_seq=100,则表示序列号在 100 之前的数据均已被用户读取，
   * 序列号为 100 以后（包括 100）的数据尚未被用户读取。
  */
  unsigned long			copied_seq;
  /* 表示目前本地接收到的对本地发送数据的应答序列号。如 acked_seq=12345, 
  则表示本地之前发送的序列号小于 12345 的所有数据已被远端成功接收 */
  unsigned long			rcv_ack_seq;
  /*/窗口大小，是一个绝对值，表示本地将要发送数据包中所包含最后一个数据的序列号不可
  大于 window_seq. window_seq 的初始化为 sent_seq 加上远端当前同胞的窗口大小，这个窗口
  大小是在 TCP 首部中窗口字段指定*/
  unsigned long			window_seq;
  /* 该字段在对方发送 FIN 数据包时使用，在接收到远端发送的 FIN 数据包后，fin_seq 被
  初始化为对方的 FIN 数据包最后一个字节的序列号加 1，表示本地对对方此 FIN 数据包进
  行应答的序列号。*/
  unsigned long			fin_seq;
  /*以下两个字段用于紧急数据处理，urg_seq 表示紧急数据最大序列号。urg_data 是一个标志
  位，当设置为 1 时，表示接收到紧急数据。*/
  unsigned long			urg_seq;
  unsigned long			urg_data;

  /*
   * Not all are volatile, but some are, so we
   * might as well say they all are.
   */
  volatile char                 inuse,  // inuse=1 表示其它进程正在使用该 sock 结构，本进程需等待。
				dead,  // dead=1 表示该 sock 结构已处于释放状态
				urginline,  // urginline=1 表示紧急数据将被当作普通数据处理
				intr,
				blog, // blog=1 表示对应套接字处于节制状态，此时接收的数据包均被丢弃
				done,
				reuse,
				keepopen, // keepopen=1 表示使用保活定时器
				linger, // linger=1 表示在关闭套接字时需要等待一段时间以确认其已关闭
				delay_acks, // delay_acks=1 表示延迟应答，可一次对多个数据包进行应答
				destroy,   // destroy=1 表示该 sock 结构等待销毁
				ack_timed,
				no_check,
				zapped,	/* In ax25 & ipx means not linked */
				broadcast,
				nonagle;  // noagle=1 表示不使用 NAGLE 算法
  unsigned long		        lingertime; // 表示等待关闭操作的时间，只有当 linger 标志位为 1 时，该字段才有意义
  int				proc; // 该 sock 结构（即该套接字）所属的进程的进程号
  struct sock			*next;
  struct sock			*prev; /* Doubly linked chain.. */
  struct sock			*pair;
  //send_head, send_tail 可靠性。用于 TCP 协议重发队列，缓存已发送出去但尚未得到对方应答的数据包
  struct sk_buff		* volatile send_head;
  struct sk_buff		* volatile send_tail;
  struct sk_buff_head		back_log; // 接收的数据包缓存队列
  // 用于创建最大长度的待发送数据包。该队列只缓存一个数据包，当该数据包长度大于 MSS 值时，将被发送出去或者缓存到其它队列上
  struct sk_buff		*partial;
  struct timer_list		partial_timer; // 定时器用于按时发送 partial 指针指向的数据包，以免缓存（等待）时间过长
  long				retransmits;  // 重发次数

  /**
   * write_queue指向待发送数据包，该队列缓存所有由于窗口限制或者由于本地节制而缓存下来的
   * 数据包，该队列中可以无限制的缓存被节制下来的数据包。
   * 该队列中数据包将由 tcp_write_xmit 函数负责发送出去，tcp_write_xmit 函数被 tcp_ack 调用，而 tcp_ack 函数用于处理接收到的应答数据包。
   * send_head,send_tail队列中数据包均已经发送出去，但尚未接收到应答。而 write_queue中数据包尚未发送。
  */
  /* 
  receive-queue 为读队列，其不同于 back_log 队列之处在于 back_log 队列缓存从网络层传
  上来的数据包，在用户进行读取操作时，不可操作 back_log 队列，而是从 receive_queue 
  队列中去数据包读取其中的数据，即数据包首先缓存在 back_log 队列中，然后从 back_log 
  队列中移动到 receive_queue 队列中方可被应用程序读取。而并非所有 back_log 队列中缓
  存的数据包都可以成功的被移动到 receive_queue 队列中，如果此刻读缓存区太小，则当
  前从 back_log 队列中被取下的被处理的数据包将被直接丢弃，而不会被缓存到。
  receive_queue 队列中。如果从应答的角度看，在 back_log 队列中的数据包由于有可能被
  丢弃，故尚未应答，而将一个数据包从 back_log 移动到 receive_queue 时，表示该数据包
  已被正式接收，即会发送对该数据包的应答给远端表示本地已经成功接收该数据包。 */
  struct sk_buff_head		write_queue,
				receive_queue;  // 全连接队列
  /*prot 字段是一个 proto 结构类型。
  该 proto 结构也是主要由一些函数指针组成。另外由于传输层所使用协议的不同，故将对应不同
  的函数集。如果使用 TCP 协议则 prot 字段指向 TCP 协议操作函数集*/
  struct proto			*prot;  // 重要字段，指向传输层处理函数集
  struct wait_queue		**sleep;
  unsigned long			daddr;  // sock 结构所代表套接字的远端地址
  unsigned long			saddr;  // 本地地址
  unsigned short		max_unacked;  // 最大未处理请求连接数（应答数）
  unsigned short		window; // 远端窗口大小  TODO:不是本地吗
  unsigned short		bytes_rcv;  // 该套接字已接收字节总数
/* mss is min(mtu, max_window) */
  unsigned short		mtu;       /* mss negotiated in the syn's */
  volatile unsigned short	mss;       /* current eff. mss - can change 最大报文长度：MSS=MTU-IP 首部长度-TCP 首部长度*/
  volatile unsigned short	user_mss;  /* mss requested by user in ioctl 用户指定的 MSS 值 */
  volatile unsigned short	max_window; // 最大窗口大小
  unsigned long 		window_clamp; // 窗口大小钳制值
  unsigned short		num;  // 本地端口号
  // 以下三个字段用于拥塞算法
  volatile unsigned short	cong_window;  // 拥塞窗口大小，表示的是本地最大可同时发送但未得到应答的数据包个数
  volatile unsigned short	cong_count;
  volatile unsigned short	ssthresh;
  volatile unsigned short	packets_out;  // 本地已发送出去但尚未得到应答的数据包数目
  volatile unsigned short	shutdown; // 本地关闭标志位，用于半关闭操作
  volatile unsigned long	rtt;  // 往返时间估计值
  volatile unsigned long	mdev; // mean deviation, 即 RTTD, 绝对偏差
  volatile unsigned long	rto;  // RTO 是用 RTT 和 mdev 用算法计算出的延迟时间值。
/* currently backoff isn't used, but I'm maintaining it in case
 * we want to go back to a backoff formula that needs it
 */
  volatile unsigned short	backoff;  // 退避算法度量值
  volatile short		err;  // 错误标志值
  unsigned char			protocol; // 传输层协议值
  volatile unsigned char	state;  // 套接字状态值，如 TCP_ESTABLISHED
  volatile unsigned char	ack_backlog;  // 缓存的未应答数据包个数
  unsigned char			max_ack_backlog;  // 最大缓存的未应答数据包个数
  unsigned char			priority;  // 该套接字优先级，在硬件缓存发送数据包时使用
  unsigned char			debug;
  unsigned short		rcvbuf;  // 最大接收缓冲区大小
  unsigned short		sndbuf; // 最大发送缓冲区大小
  unsigned short		type;  // 类型值如 SOCK_STREAM
  unsigned char			localroute;	/* Route locally only localroute=1 表示只使用本地路由，一般目的端在相同子网时使用 */
#ifdef CONFIG_IPX
  ipx_address			ipx_dest_addr;
  ipx_interface			*ipx_intrfc;
  unsigned short		ipx_port;
  unsigned short		ipx_type;
#endif
#ifdef CONFIG_AX25
/* Really we want to add a per protocol private area */
  ax25_address			ax25_source_addr,ax25_dest_addr;
  struct sk_buff *volatile	ax25_retxq[8];
  char				ax25_state,ax25_vs,ax25_vr,ax25_lastrxnr,ax25_lasttxnr;
  char				ax25_condition;
  char				ax25_retxcnt;
  char				ax25_xx;
  char				ax25_retxqi;
  char				ax25_rrtimer;
  char				ax25_timer;
  unsigned char			ax25_n2;
  unsigned short		ax25_t1,ax25_t2,ax25_t3;
  ax25_digi			*ax25_digipeat;
#endif  
#ifdef CONFIG_ATALK
  struct atalk_sock		at;
#endif

/* IP 'private area' or will be eventually */
  int				ip_ttl;		/* TTL setting */
  int				ip_tos;		/* TOS */
  struct tcphdr			dummy_th; // 缓存的 TCP 首部，在 TCP 协议中创建一个发送数据包时可以利用此字段快速创建 TCP首部

  // 保活定时器，用于探测对方窗口大小，防止对方通报窗口大小的数据包丢弃，从而造成本地发送通道被阻塞
  struct timer_list		keepalive_timer;	/* TCP keepalive hack */

  // 重发定时器，用于数据包超时重发
  struct timer_list		retransmit_timer;	/* TCP retransmit timer */

  // 延迟应答定时器，延迟应答可以减少应答数据包的个数，但不可无限延迟以免造成远端重发，所以设置定时器定期发送应答数据包
  struct timer_list		ack_timer;		/* TCP delayed ack timer */

  // 该字段为标志位组合字段，用于表示下文中 timer 定时器超时的原因
  int				ip_xmit_timeout;	/* Why the timeout is running */
#ifdef CONFIG_IP_MULTICAST  
  int				ip_mc_ttl;			/* Multicasting TTL */
  int				ip_mc_loop;			/* Loopback (not implemented yet) */
  char				ip_mc_name[MAX_ADDR_LEN];	/* Multicast device name */
  struct ip_mc_socklist		*ip_mc_list;			/* Group array */
#endif  

  /* This part is used for the timeout functions (timer.c). */
  /* 以下两个字段用于通用定时，timeout 表示定时时间值，ip_xmit_timeout 表示此次定时的原因，timer 为定时器。 */
  int				timeout;	/* What are we waiting for? */
  struct timer_list		timer;		/* This is the TIME_WAIT/receive timer when we are doing IP */
  struct timeval		stamp;  // 时间戳

  /* identd */
  /*一个套接字在不同的层次上分别由 socket 结构和 sock 结构表示，该 socket 字段用于指向
  其对应的 socket 结构以便对某些信息的快速获取。同理在 socket 结构中也有指向 sock 
  结构的指针。*/
  struct socket			*socket;
  
  /* Callbacks */
  //以下四个函数指针字段指向回调函数。这些字段的设置为自定义回调函数提供的很大的
  //灵活性，内核在发生某些时间时，会调用这些函数，如此可以实现自定义响应。目前这
  //种自定义响应还是完全有内核控制。
  void				(*state_change)(struct sock *sk);
  void				(*data_ready)(struct sock *sk,int bytes);
  void				(*write_space)(struct sock *sk);
  void				(*error_report)(struct sock *sk);
  
};

/* 对于每个传输层协议都有一个 proto 结构对应，如 TCP 协议的 tcp_proto， UDP 协议的 udp_proto。
这里的函数都是完成具体操作的，比如应用程序调用 connect 函数，connect 函数的内核处理函数为 sys_socket 入口函数，sys_socket 
入口函数调用对应的 sock_connect 函数，sock_connect 调用 inet_connect, inet_connect 调用
tcp_connect, tcp_connect 根据 TCP 协议的规范完成具体的连接操作（即进行三路握手连接） */
struct proto {
  struct sk_buff *	(*wmalloc)(struct sock *sk,
				    unsigned long size, int force,
				    int priority);
  struct sk_buff *	(*rmalloc)(struct sock *sk,
				    unsigned long size, int force,
				    int priority);
  void			(*wfree)(struct sock *sk, struct sk_buff *skb,
				 unsigned long size);
  void			(*rfree)(struct sock *sk, struct sk_buff *skb,
				 unsigned long size);
  unsigned long		(*rspace)(struct sock *sk);
  unsigned long		(*wspace)(struct sock *sk);
  void			(*close)(struct sock *sk, int timeout);
  int			(*read)(struct sock *sk, unsigned char *to,
				int len, int nonblock, unsigned flags);
  int			(*write)(struct sock *sk, unsigned char *to,
				 int len, int nonblock, unsigned flags);
  int			(*sendto)(struct sock *sk,
				  unsigned char *from, int len, int noblock,
				  unsigned flags, struct sockaddr_in *usin,
				  int addr_len);
  int			(*recvfrom)(struct sock *sk,
				    unsigned char *from, int len, int noblock,
				    unsigned flags, struct sockaddr_in *usin,
				    int *addr_len);
  int			(*build_header)(struct sk_buff *skb,
					unsigned long saddr,
					unsigned long daddr,
					struct device **dev, int type,
					struct options *opt, int len, int tos, int ttl);
  int			(*connect)(struct sock *sk,
				  struct sockaddr_in *usin, int addr_len);
  struct sock *		(*accept) (struct sock *sk, int flags);
  void			(*queue_xmit)(struct sock *sk,
				      struct device *dev, struct sk_buff *skb,
				      int free);
  void			(*retransmit)(struct sock *sk, int all);
  void			(*write_wakeup)(struct sock *sk);
  void			(*read_wakeup)(struct sock *sk);
  int			(*rcv)(struct sk_buff *buff, struct device *dev,
			       struct options *opt, unsigned long daddr,
			       unsigned short len, unsigned long saddr,
			       int redo, struct inet_protocol *protocol);
  int			(*select)(struct sock *sk, int which,
				  select_table *wait);
  int			(*ioctl)(struct sock *sk, int cmd,
				 unsigned long arg);
  int			(*init)(struct sock *sk);
  void			(*shutdown)(struct sock *sk, int how);
  int			(*setsockopt)(struct sock *sk, int level, int optname,
  				 char *optval, int optlen);
  int			(*getsockopt)(struct sock *sk, int level, int optname,
  				char *optval, int *option);  	 
  unsigned short	max_header;
  unsigned long		retransmits;
  struct sock *		sock_array[SOCK_ARRAY_SIZE];
  char			name[80];
  int			inuse, highestinuse;
};

#define TIME_WRITE	1
#define TIME_CLOSE	2
#define TIME_KEEPOPEN	3
#define TIME_DESTROY	4
#define TIME_DONE	5	/* used to absorb those last few packets */
#define TIME_PROBE0	6
#define SOCK_DESTROY_TIME 1000	/* about 10 seconds			*/

#define PROT_SOCK	1024	/* Sockets 0-1023 can't be bound too unless you are superuser */

#define SHUTDOWN_MASK	3
#define RCV_SHUTDOWN	1
#define SEND_SHUTDOWN	2


extern void			destroy_sock(struct sock *sk);
extern unsigned short		get_new_socknum(struct proto *, unsigned short);
extern void			put_sock(unsigned short, struct sock *); 
extern void			release_sock(struct sock *sk);
extern struct sock		*get_sock(struct proto *, unsigned short,
					  unsigned long, unsigned short,
					  unsigned long);
extern struct sock		*get_sock_mcast(struct sock *, unsigned short,
					  unsigned long, unsigned short,
					  unsigned long);
extern struct sock		*get_sock_raw(struct sock *, unsigned short,
					  unsigned long, unsigned long);

extern struct sk_buff		*sock_wmalloc(struct sock *sk,
					      unsigned long size, int force,
					      int priority);
extern struct sk_buff		*sock_rmalloc(struct sock *sk,
					      unsigned long size, int force,
					      int priority);
extern void			sock_wfree(struct sock *sk, struct sk_buff *skb,
					   unsigned long size);
extern void			sock_rfree(struct sock *sk, struct sk_buff *skb,
					   unsigned long size);
extern unsigned long		sock_rspace(struct sock *sk);
extern unsigned long		sock_wspace(struct sock *sk);

extern int			sock_setsockopt(struct sock *sk,int level,int op,char *optval,int optlen);

extern int			sock_getsockopt(struct sock *sk,int level,int op,char *optval,int *optlen);
extern struct sk_buff 		*sock_alloc_send_skb(struct sock *skb, unsigned long size, int noblock, int *errcode);
extern int			sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);

/* declarations from timer.c */
extern struct sock *timer_base;

void delete_timer (struct sock *);
void reset_timer (struct sock *, int, unsigned long);
void net_timer (unsigned long);


#endif	/* _SOCK_H */
